<template>
    <div ref="dragContainerRef" class="drag-container" @drop="drop">
        <DragItem v-for="(item, index) in list" :key="index" style="width: 500px;" :data-key="item[idKey]">
            <slot :item="item"></slot>
        </DragItem>
    </div>
</template>

<script setup lang="ts">
import { defineProps, provide, ref, defineEmits } from 'vue'
import { DragContext, DragProvider } from './constants';
import DragItem from '@/components/DragSort/DragItem.vue';

defineProps<{ list: any[]; idKey: string; }>()
const emits = defineEmits(['change'])

let childrens: HTMLElement[] = []
const dragContainerRef = ref<HTMLElement>()
const offsetY = ref(0)
let currentDragElement: HTMLElement | null = null

function drop(ev: DragEvent) {
    ev.preventDefault();
}

provide<DragContext>(DragProvider, {
    deregistration: (el: HTMLElement) => {
        childrens = childrens.filter(item => item !== el)
    },
    register: (el: HTMLElement) => {
        if(childrens.find(_el => _el === el)) {
            return
        }
        el.addEventListener('dragstart', (ev) => {
            currentDragElement = ev.target as HTMLElement
            currentDragElement.style.opacity = '0'
            offsetY.value = ev.offsetY
        })

        el.addEventListener('dragenter', (ev) => {
            const target = ev.target as HTMLElement
            let parent: HTMLElement | null = target.parentNode as HTMLElement
            // eslint-disable-next-line no-constant-condition
            while(true) {
                if(!parent || parent === document.body || parent === dragContainerRef.value) {
                    parent = null
                    break
                } else if(childrens.find(_el => _el === parent)) {
                    break
                }
                parent = parent.parentNode as HTMLElement
            }

            if(!parent) {
                return
            }

            if(parent !== currentDragElement && currentDragElement) {
                if(offsetY.value < ev.offsetY) {
                    parent.before(currentDragElement)
                    return
                }
                parent.after(currentDragElement)
            }
            
        })
        childrens.push(el)
    },
    dragEnd: () => {
        if(!currentDragElement) {
            return
        }
        currentDragElement.style.opacity = '1'
        currentDragElement = null

        if(!dragContainerRef.value) {
            return
        }
        const children = [...dragContainerRef.value.children] || []
        const keys: string[] = []
        children.forEach(child => {
            const key = child.getAttribute('data-key')
            if(key) {
                keys.push(key)
            }
        })
        console.log(keys);
        emits('change', keys)
    },
})
</script>